package com.googlecode.gwtbb.server.intermediate.picture;

import com.googlecode.gwtbb.client.shared.entity.picture.ImageProperties;
import com.googlecode.gwtbb.client.shared.entity.picture.Picture;
import com.googlecode.gwtbb.client.shared.entity.picture.Thumb;
import com.googlecode.gwtbb.client.shared.util.PictureUtils;
import com.googlecode.gwtbb.client.shared.util.StringUtils;
import com.googlecode.gwtbb.server.dao.picture.PictureDao;
import com.googlecode.gwtbb.server.intermediate.FileOrganizer;
import org.apache.commons.fileupload.FileItem;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.*;

/**
 * @author Abraham Grief
 * @version $Id$
 * @since Aug 2, 2008
 */
public class PictureFileOrganizer extends FileOrganizer {
	//private static Log log = LogFactory.getLog(PictureFileOrganizer.class);

	private static final char urlSeparatorChar = '/';
	private PictureDao pictureDao;
	private String pictureUrlBase;
	private Collection<Thumbnailer> thumbnailers;

	public PictureDao getPictureDao() {
		return pictureDao;
	}

	public void setPictureDao(PictureDao pictureDao) {
		this.pictureDao = pictureDao;
	}

	public String getPictureUrlBase() {
		return pictureUrlBase;
	}

	public void setPictureUrlBase(String pictureUrlBase) {
		this.pictureUrlBase = pictureUrlBase;
	}

	public Collection<Thumbnailer> getThumbnailers() {
		return thumbnailers;
	}

	public void setThumbnailers(Collection<Thumbnailer> thumbnailers) {
		this.thumbnailers = thumbnailers;
	}

	public Picture fillPicture(String fileName) {
		Picture picture = new Picture();
		fillPicture(picture, fileName);
		return picture;
	}

	public void fillPicture(Picture picture, String fileName) {
		fileName = ensureSeparator(fileName);
		picture.setPictureId(pictureIdFromFileName(fileName));
		String fullPath = getFileBaseDir() + File.separator + fileName;
		fillImageProperties(picture, fileName, fullPath);
	}

	public List<Thumb> fillThumbs(String pictureFileName) {
		pictureFileName = ensureSeparator(pictureFileName);
		List<Thumb> retVal = null;
		final String pictureIdStr = pictureIdStrFromFileName(pictureFileName);
		final String pictureFullPath = getFileBaseDir() + File.separator + pictureFileName;
		final int nameBegin = pictureFullPath.lastIndexOf(File.separator);
		File dir = new File(pictureFullPath.substring(0, nameBegin));
		String[] thumbFileNames = dir.list(new FilenameFilter() {
			final String picFileName = pictureFullPath.substring(nameBegin + 1);

			public boolean accept(File dir, String name) {
				return name.startsWith(pictureIdStr) && !name.equals(picFileName);
			}
		});
		if (thumbFileNames != null) {
			int numThumbs = thumbFileNames.length;
			retVal = new ArrayList<Thumb>(numThumbs);
			for (int i = 0; i < numThumbs; i++) {
				String organizedPath = pictureFullPath.substring(getFileBaseDir().length() + 1, nameBegin);
				String thumbFileName = organizedPath + File.separator + thumbFileNames[i];
				String thumbFullPath = getFileBaseDir() + File.separator + thumbFileName;
				Thumb thumb = new Thumb();
				thumb.setPictureId(Long.valueOf(pictureIdStr));
				fillImageProperties(thumb, thumbFileName, thumbFullPath);
				retVal.add(thumb);
			}
		}
		return retVal;
	}

	public String getAdditionalInfo(File file) {
		String retVal = "";
		String fileName = getOrganizedPath(file);
		List<Thumb> thumbs = fillThumbs(fileName);
		if (thumbs != null && !thumbs.isEmpty()) {
			long minBytes = Long.MAX_VALUE;
			for (Thumb thumb : thumbs)
				if (thumb.getBytes() < minBytes) {
					minBytes = thumb.getBytes();
					retVal = thumb.getUrl();
				}
		} else {
			retVal = fillPicture(fileName).getUrl();
		}
		return retVal;
	}

	/*
 */
	
	@Override
	public String getFileName(String clientFileName, File tmpFile) throws IOException {
		String extension = StringUtils.getExtension(clientFileName);
		if (extension == null)
			throw new IllegalArgumentException("filename without extension: " + clientFileName);
		if ("jpeg".equals(extension))
			extension = "jpg";
		BufferedImage srcImage = ImageIO.read(tmpFile);
		return PictureUtils.getPicFileName(pictureDao.generateId().toString(), srcImage.getWidth(), srcImage.getHeight(), extension);
	}

	/*
	 public String getThumbPath(String imgPath) {
		 int extIndex = imgPath.lastIndexOf(StringUtils.EXT_DELIM);
		 return imgPath.substring(0, extIndex) + thumbMark + imgPath.substring(extIndex);
	 }
 */
	public String pictureUrl(String fileName) {
		if (File.separatorChar != urlSeparatorChar)
			fileName = fileName.replace(File.separatorChar, urlSeparatorChar);
		// pictureUrlBase should end with urlSeparatorChar
		return pictureUrlBase + fileName;
	}

	public File writeFile(FileItem fileItem) throws ServletException, IOException {
		File file = super.writeFile(fileItem);
		if (thumbnailers != null)
			for (Thumbnailer thumbnailer : thumbnailers)
				if (!thumbnailer.createThumbnail(file))
					break;
		return file;
	}

	private void fillImageProperties(ImageProperties imageProperties, String fileName, String fullPath) {
		File file = new File(fullPath);
		if (!file.exists())
			throw new IllegalStateException("specified file does not exist: " + fileName);
		imageProperties.setBytes(file.length());

		int widthStart = fileName.indexOf("_");
		int heightStart = fileName.indexOf("x", ++widthStart);
		int width = Integer.parseInt(fileName.substring(widthStart, heightStart++));
		int heightEnd = fileName.indexOf(StringUtils.EXT_DELIM, heightStart);
		int height = Integer.parseInt(fileName.substring(heightStart, heightEnd));
		imageProperties.setWidth(width);
		imageProperties.setHeight(height);

		imageProperties.setUrl(pictureUrl(fileName));
	}

	private Long pictureIdFromFileName(String fileName) {
		return Long.valueOf(pictureIdStrFromFileName(fileName));
	}

	private String pictureIdStrFromFileName(String fileName) {
		int begin = fileName.lastIndexOf(File.separatorChar) + 1;
		if (begin < 0)
			throw new IllegalStateException("bad picture fileName: " + fileName);
		int end = fileName.indexOf("_", begin);
		if (end < begin)
			throw new IllegalStateException("bad picture fileName: " + fileName);
		return fileName.substring(begin, end);
	}
}
